package m.jclecai.com.view.common;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;


/**
 * Created by andy on 2017/6/6.
 * 这里的话，我们是不支持无平滑过渡，无平滑过渡就会产生一个bug，导致出现问题；
 */
public class VeticalDrawerLayout extends FrameLayout {

    ViewDragHelper mDragHelper;
    private ViewGroup mInnerLayout;
    private ViewGroup mOutterLayout;
    private int mInnerLayoutHeight;
    private int mOutterHeight;
    private int mOutterWidth;
    private int mPullLayoutHeight;

    //这里表示可以向上移动的距离；
    private int mInnerTopMargin;
    private int INNER_LAYOUT_MARGIN;

    public VeticalDrawerLayout(Context context) {
        this(context,null);
    }

    public VeticalDrawerLayout(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public VeticalDrawerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mDragHelper = ViewDragHelper.create(this,callBack);

    }

    private int mCurrentTop;

    //这里话，我们要做的一个操作就复杂了，由之前的水平，我们将换成垂直方向上的；
    ViewDragHelper.Callback callBack = new ViewDragHelper.Callback() {

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //如果是外边的布局我们就尝试捕获；
            return child== mOutterLayout;
        }

        @Override
        public int getViewVerticalDragRange(View child) {
            return mInnerLayoutHeight;
        }

        //这里表示将要移动但是还没有移动的情况；
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            //这里的话， 我们要做的一个操作就是对移动的位置进行一个修正；
            if(child==mOutterLayout){
                top=fixTop(top);
            }
            return top;
        }

        //这个方法里面我们要做的一个操作就是联动的实现；
        // 这里我们通过重新布局的方式来实现的，原因在于我们可以防止由于其他的因素影响导致，onLayout重新布局出现问题；
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {


            mInnerLayout.setVisibility((changedView.getHeight() - top == getHeight()) ? View.GONE : View.VISIBLE);

            //通过mCurrentTop来移动外边的layout
            mCurrentTop =top ;
            //计算移动的百分比；
            float percent = top * 1.0f / mInnerLayoutHeight;
            //根据这个百分比我们将实现相应的动画；
            Float evaluate = evaluate(percent, 0, Math.abs(INNER_LAYOUT_MARGIN));
            mInnerTopMargin=INNER_LAYOUT_MARGIN+new Float(evaluate).intValue();
            requestLayout();
            dispachDragEvent(top);
            invalidate();
        }

        //这里的话，我们是需要处理手指松动的动画的逻辑；
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            System.out.println("yvel: "+yvel+ "mInnerLayoutHeight:"+mInnerLayoutHeight+"==top:"+mOutterLayout.getTop());
            if(mOutterLayout.getTop()<0){

            } else if(yvel==0 && mOutterLayout.getTop()>mInnerLayoutHeight/2){
                //这样的话，我们也是认为其是打开的；
                open();
            }else if(yvel>2000){
                //速度大于2000才让其打开，因为防止误操作,这里的话表示的是打开的；
                open();
            }else{
                //这里的话表示是关闭；
                close();
            }
        }
    };



    //这里的话，我们是需要关闭的；
    public void close() {

        smoothClose(true);
    }


    //打开的；
    public void open() {
        smoothOpen(true);
    }

    private void smoothOpen(boolean isSmooth) {

        if(isSmooth){
            if(mDragHelper.smoothSlideViewTo(mOutterLayout, 0, mInnerLayoutHeight)) {
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }else{
            //暂时不做；
        }
    }

    @Override
    public void computeScroll() {
        if(mDragHelper.continueSettling(true)){
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    private void smoothClose(boolean isSmooth) {

        if (isSmooth) {

            if(mDragHelper.smoothSlideViewTo(mOutterLayout, 0, 0)){
                ViewCompat.postInvalidateOnAnimation(this);
            }

        }else{
            //暂时不做
        }

    }

    public OnDragStatusChange mOnDragStatusChange;

    public void setOnDragStatusChange(OnDragStatusChange onDragStatusChange) {
        mOnDragStatusChange = onDragStatusChange;
    }

    //暴露接口；
    public interface OnDragStatusChange{
        void onOpen();
        void onClose();
        void OnDrag(float percent);
    }

    public void toggle(){
        if(mCurStaus== Status.close){
            open();
        }else{
            close();
        }
    }


    public enum Status{
        open,close,dragging
    }

    public Status mCurStaus= Status.close;

    //这里我将事件暴露出去，供别人使用；这里的话，我们应该将进度的百分比给弄出去，
    // 这样的话，如果有其他的动画需要联动的话，我们我们也是可以实现联动的效果；
    private void dispachDragEvent(int fixTop) {
        //这里的话，我们获取得到百分比；
        float percent = fixTop * 1.0f / mInnerLayoutHeight;
        if (mOnDragStatusChange == null) {
            return;
        }
        //这里如果不设置状态的话，我们在外边是没有办法点击打开的；

        mCurStaus= updateDragStatus(percent);
        if(mCurStaus.equals(Status.open)){
            mOnDragStatusChange.onOpen();
        }else if(mCurStaus.equals(Status.close)){
            mOnDragStatusChange.onClose();
        }else {
            mOnDragStatusChange.OnDrag(percent);
        }
    }

    private Status updateDragStatus(float percent) {
        //这里我们要实现相应的功能；
        if(percent==0){
            return Status.close;
        }else if(percent==1){
            return Status.open;
        }
        return Status.dragging;
    }

    //这里的话，我们将进行一个动画，；
    private void startAnim(int fixTop) {
        //这里的话，我们在拖动OutLayout的时候，我们是需要InnerLayout有一个慢慢的向下的滚动的动画；
        float percent = fixTop * 1.0f / mInnerLayoutHeight;
        //根据这个百分比我们将实现相应的动画；
        Float evaluate = evaluate(percent, 0, dip2px(getContext(),50));

        mInnerTopMargin=new Float(evaluate).intValue();
        mInnerLayout.setTranslationY(evaluate);
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }


    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }


    /**
     * 这里我们对高度进行一个修正，
     * @param top
     * @return
     */
    private int fixTop(int top) {
        //这里的话，我们要对其进行一个修正；
        if(top<5){
            top=0;
        }else if(top>mInnerLayoutHeight){
            top=mInnerLayoutHeight;
        }
        return top;
    }

    /**
     * 这里的话，我们将进行的一个操作就是获取子布局；
     * 当我们拖动外边的布局的时候，里面的布局其实是会发生变化的；
     */
    @Override
    protected void onFinishInflate() {
        mInnerLayout = ((ViewGroup) getChildAt(0));
        mOutterLayout = ((ViewGroup) getChildAt(1));

        FrameLayout.LayoutParams layoutParams = (LayoutParams) mInnerLayout.getLayoutParams();
        //这个表示上边距，是一个负数，我们是需要将其移动到一个正数；
        INNER_LAYOUT_MARGIN = layoutParams.topMargin;
        //对向上移动的margin进行一个赋值；
        mInnerTopMargin=INNER_LAYOUT_MARGIN;
        System.out.println("innerTopMargin: "+mInnerTopMargin);

    }

    /**
     * 这里我们是可以获取布局的相应的高度的；我们通过滑动布局的相应的高度；
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //这个是里面的布局的一个高度；这里-2的原因，在我的手机上，有时候会出现空隙的现象，

        mInnerLayoutHeight = mInnerLayout.getMeasuredHeight() - 2;
        mOutterHeight = mOutterLayout.getMeasuredHeight();
        mOutterWidth = mOutterLayout.getMeasuredWidth();

        System.out.println(" OutterHeight: "+mOutterHeight+" pullLayoutHeight: "+mPullLayoutHeight);
    }


    public void measureInnerLayout(){
        int measureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
        mInnerLayout.measure(measureSpec,measureSpec);
        mInnerLayoutHeight = mInnerLayout.getMeasuredHeight() - 2;
    }

    public void measuerOutterLayout(){
        int measureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
        mOutterLayout.measure(measureSpec,measureSpec);
        mOutterHeight = mOutterLayout.getMeasuredHeight();
    }

    float downX;
    float downY;


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //这里我们做一个判断如果是水平的滑动我们是不处理的；
        float curX=0;
        float curY=0;

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = ev.getRawX();
                downY = ev.getRawY();
            case MotionEvent.ACTION_MOVE:

                curX = ev.getRawX();
                curY = ev.getRawY();

                float dx = Math.abs(curX - downX);
                float dy = Math.abs(curY - downY);

                System.out.println("移动的距离：" + "dx： " + dx + " dy: " + dy);
                //水平方向的滑动近距离大于竖直方向的的时候，我们是让ViewPager自己处理点击事件；
                if (dx > dy) {
                    return false;
                }
                break;
            default:
                break;
        }
        boolean b = mDragHelper.shouldInterceptTouchEvent(ev);
        System.out.println("VeticalDrawerLayout:onInterceptTouchEvent: "+b);
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将事件交给ViewDragHelper来处理；
        mDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {


        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(measureWidth, measureHeight);
        //这里我们对两个子类进行一个测量；
        //里面的布局包裹内容就可以了
       /* measureChildWithMargins(mInnerLayout,widthMeasureSpec,0,heightMeasureSpec,0);
        //外边的布局始终和父布局一样大
        mOutterLayout.measure(
                MeasureSpec.makeMeasureSpec(measureWidth,MeasureSpec.EXACTLY)
                ,
                MeasureSpec.makeMeasureSpec(measureHeight,MeasureSpec.EXACTLY)
                );*/

        measureChild(mInnerLayout,widthMeasureSpec,heightMeasureSpec);
        measureChild(mOutterLayout,widthMeasureSpec,heightMeasureSpec);


        int measuredHeight = mInnerLayout.getMeasuredHeight();
        int measuredHeight1 = mOutterLayout.getMeasuredHeight();

    }



    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        //super.onLayout(changed, left, top, right, bottom);
        //这里的话，这个也应该是一个动态的；
        mInnerLayout.layout(0,mInnerTopMargin,
                mInnerLayout.getMeasuredWidth(),
                mInnerTopMargin+mInnerLayoutHeight);

        mOutterLayout.layout(0, mCurrentTop,
                mOutterLayout.getMeasuredWidth(),
                mCurrentTop + mOutterHeight);
    }
}

